package com.woniuxy.house.advice;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.woniuxy.entity.house.dto.RenthouseDto;
import com.woniuxy.entity.house.dto.RenthouseQO;
import com.woniuxy.entity.house.dto.SecondHouseTypeDto;
import com.woniuxy.entity.house.dto.SecondhouseQO;
import com.woniuxy.house.mapper.RenthouseMapper;
import com.woniuxy.house.mapper.SecondhouseMapper;
import com.woniuxy.house.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Component
@Aspect
@Slf4j
public class RedisAdvice {
    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private RenthouseMapper renthouseMapper;

    @Resource
    private SecondhouseMapper secondhouseMapper;

    //1.配置切点
    @Pointcut("execution(* com.woniuxy.house.service.impl.*.find*(..))")
    public void findCache(){}

    @Pointcut("execution(* com.woniuxy.house.service.impl.*.update*(..)) || execution(* com.woniuxy.house.service.impl.*.delete*(..))")
    public void deleteCache(){}

    //2.环绕通知
    @Around("findCache()")
    public Object findCache(ProceedingJoinPoint joinPoint) {
        // 获取类名、方法名
        String className=joinPoint.getSignature().getDeclaringTypeName();
        String methodName = joinPoint.getSignature().getName();
        //获取对象的参数
        Object[] args = joinPoint.getArgs();
        // 根据生成策略生成key
        String key = RedisUtil.findKey(className,methodName,args);
        // 判断key是否存在   存在获取返回
        if (redisTemplate.hasKey(key)) {
            log.info("从redis中获取数据");
            // 有数据则直接返回
            return redisTemplate.opsForValue().get(key);
        }
        // 没有数据就调用方法去数据库查数据
        Object object = null;
        try {
            object = joinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        // 得到数据之后存到redis中，并设置过期时间10分钟
        if(object != null){
            if(object instanceof Page){
                List<?> list = ((Page<?>) object).getRecords();
                if(list != null && Objects.requireNonNull(list).size() != 0){
                    redisTemplate.opsForValue().set(key,object,60 * 10 + new Random().nextInt(600), TimeUnit.SECONDS);
                }else{
                    redisTemplate.opsForValue().set(key,null,30,TimeUnit.SECONDS);
                }
            }else {
                redisTemplate.opsForValue().set(key,object,60 * 10  + new Random().nextInt(600), TimeUnit.SECONDS);
            }
        }else{
            redisTemplate.opsForValue().set(key,null,30,TimeUnit.SECONDS);
        }
        // 返回数据
        return object;
    }

    @Around("deleteCache()")
    public Object deleteCache(ProceedingJoinPoint joinPoint) {
        // 获取类名、方法名
        String className=joinPoint.getSignature().getDeclaringTypeName();

        String key = RedisUtil.delKey(className) + "*";
        Set<String> keys = redisTemplate.keys(key);

        Object object = null;
        try {
            object = joinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        // 修改成功，才操作redis
        if((boolean) object){
            // 如果数据库中有数据，则删除该条数据，因为要进行修改
            if (CollectionUtils.isNotEmpty(keys)) {
                log.info("redis中有相关数据，防止读取到修改前数据，进行删除");
                redisTemplate.delete(keys);
                // 再重新将热点数据放入 redis中
                Page<RenthouseDto> page = renthouseMapper.findLike(new Page<>(1, 10), new RenthouseQO());
                redisTemplate.opsForValue().set("find:com.woniuxy.house.service.impl.RenthouseServiceImplfindLike:1:10:" +
                        "RenthouseQO(minFloor=null, maxFloor=null, houseHead=null, elevator=null, " +
                        "rentway=null, minPrice=null, maxPrice=null, sortPrice=null)",page);
                Page<SecondHouseTypeDto> page2 = secondhouseMapper.findLike(new Page<>(1, 10), new SecondhouseQO());
                redisTemplate.opsForValue().set("find:com.woniuxy.house.service.impl.SecondhouseServiceImplfindLike:1:10:" +
                        "SecondhouseQO(description=null, minFloor=null, maxFloor=null, minPrice=null, maxPrice=null, minArea=null, " +
                        "maxArea=null, houseHead=null, decorate=null, elevator=null, sortPrice=null, sortArea=null)",page2);
            }
        }
        return object;
    }
}